﻿using System;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using User.EF.Model;
using User.Global.Constvalues.Web.Navigation;

namespace User.Web.UI.Helper.RightsManagement
{
    /// <summary>
    /// Athorization Attribut, was auswertet ob die UserRolle die übergeben wurde auf die aktuelle WebAPI Funktion zugreifen darf
    /// dafür muss das Attribut gesetzt werden.
    /// Quellen für Filter und Attribute in ASP.NET MVC
    /// http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
    /// http://bstechnical.blogspot.de/2013/01/web-api-authorization.html
    /// http://remy.supertext.ch/2012/04/basic-http-authorization-for-web-api-in-mvc-4-beta/
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class CustomWebApiAuthorizeAttribute : AuthorizeAttribute
    {
        #region Member
        /// <summary>
        /// Der Aktuelle API Controller der abgefragt wird
        /// </summary>
        private EController Controller { get; set; }

        /// <summary>
        /// Die aktuelle Aktion die abgefragt wird in der WebAPI
        /// </summary>
        private string ActionName { get; set; }

        /// <summary>
        /// Die aktuell übergebene URL Id, wenn eine übergeben wurde, sonst Null
        /// </summary>
        private string Id { get; set; }

        /// <summary>
        /// Die ID des aktuell eingeloggten Benutzers
        /// </summary>
        private long CurrentUserId { get; set; }

        private HttpActionContext CurrentContext { get; set; }
        #endregion

        /// <summary>
        /// Prüfen ob der User auch Autorisiert ist, auf die passenden API Aufrufe zuzugreifen
        /// </summary>
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            //Wenn der User nicht eingeloggt ist, dann wird er hier schon mit einem 401 abgewiesen
            base.OnAuthorization(actionContext);

            //Der Filtercontext wird benötigt um auf die RequestDaten zuzugreifen, z.b. auf die UserId die zugegriffen werden soll.
            CurrentContext = actionContext;
            //Setzen des aktuellen Actionnamen, der aufgerufen wird.
            ActionName = actionContext.ActionDescriptor.ActionName;
            //Auslesen der ID, wenn eine in der URL mit übergeben wurde.
            Id = actionContext.ControllerContext.RouteData.Values.ContainsKey("id") ? actionContext.ControllerContext.RouteData.Values["id"].ToString() : null;
            //Den aktuellen CurrentController ermitteln, dieser ist in RouteData enthalten, des aktuellen filterContext. 
            string controller = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
            //string controller = actionContext.ControllerContext.RouteData.Values.ContainsKey(WebConstants.ControllerString) ? actionContext.ControllerContext.RouteData.Values[WebConstants.ControllerString].ToString() : null; 
            if (controller != null)
            {
                Controller = (EController)Enum.Parse(typeof(EController), controller);
            }
            else
            {
                HandleUnauthorizedRequest(actionContext);
            }

            //Wenn kein User eingeloggt ist, dann hat er auch keinen Zugriff.
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                HandleUnauthorizedRequest(actionContext);
            }
            else
            {
                long userId;
                //Die UserId des aktuell eingeloggten Benuzers ermitteln
                if (long.TryParse(HttpContext.Current.User.Identity.Name, out userId))
                {
                    CurrentUserId = userId;
                    //Prüfen der passenden Rechte für die einzelnen Actions/Methoden
                    //Wenn der User nicht für den View/Action authentifiziert ist, dann auf die Loginseite verweisen.
                    if (!CheckRights())
                    {
                        HandleUnauthorizedRequest(actionContext);
                    }
                }
                else
                {
                    HandleUnauthorizedRequest(actionContext);
                }
            }

            //Wenn alles i.o. ist "nichts" unternehmen und einfach beim Aufbau der Seite weitermachen.
        }

        /// <summary>
        /// Den unautorisierten Eingriff, "abwehren"
        /// </summary>
        /// <param name="actionContext"></param>
        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
            throw new HttpResponseException(challengeMessage);
        }

        #region Private Functions
        /// <summary>
        /// Prüfen um welchen CurrentController es sich handelt und die passende Sicherheitsprüfung vornehmen
        /// Hier werden Nur API Controller überprüft
        /// </summary>
        /// <returns>TRUE->Darf zugreifen | FALSE->Darf nicht zugreifen</returns>
        private bool CheckRights()
        {
            //Prüfen welcher CurrentController das Attribut aufgerufen hat und dann schauen welche Action aufgerufen wurde.
            switch (Controller)
            {
                case EController.AdminApi:
                    return CheckAdminRights();
            }

            return false;
        }

        /// <summary>
        /// Prüfen der Arbeitszeitrechte
        /// </summary>
        /// <returns>TRUE->Darf zugreifen | FALSE->Darf nicht zugreifen</returns>
        private bool CheckAdminRights()
        {
            //den passenden Enum Wert ermitteln
            EActionApiAdministration eActionWorktime = (EActionApiAdministration)Enum.Parse(typeof(EActionApiAdministration), ActionName);

            //Prüfen ob der User auf das Modul zugreifen darf, wenn nicht, dann hat er kein Recht!
            //Auf den Admin Bereich darf man nur als Admin zugreifen
            if (!WebRights.Rights().Check(EMemberRight.Administrator))
            {
                return false;
            }

            //Die einzelnen Rechte für das Modul prüfen.
            switch (eActionWorktime)
            {
                case EActionApiAdministration.MemberListFilter:
                    //Wenn man einen Fremden DS bearbeiten will, dann muss man auch das Recht dafür haben.
                    return WebRights.Rights().Check(EMemberRight.Administrator);
            }
            return false;
        }
        #endregion
    }
}


